package article_api

import (
	md "github.com/JohannesKaufmann/html-to-markdown"
	"github.com/PuerkitoBio/goquery"
	"github.com/gin-gonic/gin"
	"giv-vue-blog/global"
	"giv-vue-blog/models"
	"giv-vue-blog/models/res"
	"giv-vue-blog/service/es_ser"
	"giv-vue-blog/utils/jwts"
	"math/rand"
	"pkg/mod/github.com/russross/blackfriday"
	"strings"
	"time"
)

type ArticleRequest struct {
	Title    string   `json:"title" binding:"required" msg:"请输入文章标题"`   //文章标题
	Abstract string   `json:"abstract"`                                 //文章简介
	Content  string   `json:"content" binding:"required" msg:"请输入文章内容"` //文章内容
	Category string   `json:"category"`                                 //文章分类
	Source   string   `json:"source"`                                   //文章来源
	Link     string   `json:"link"`                                     //原文链接
	BannerID uint     `json:"banner_id"`                                //文章封面id
	Tags     []string `json:"tags"`                                     //文章标签
}

// ArticleCreateView 创建文章
// @Tags 文章管理
// @Summary 创建文章
// @Description 创建文章
// @Param data body ArticleRequest true "表示多个参数"
// @Router /api/articles [post]
// @Produce json
// @Success 200 {object} res.Response{}
func (ArticleApi) ArticleCreateView(c *gin.Context) {
	var cr ArticleRequest
	err := c.ShouldBindJSON(&cr)
	if err != nil {
		res.FailedWithError(err, &cr, c)
		return
	}
	_claims, _ := c.Get("claims")
	claims := _claims.(*jwts.CustomClaims)
	userId := claims.UserID
	userNickName := claims.NickName
	//校验content xss
	//处理content
	unsafe := blackfriday.MarkdownCommon([]byte(cr.Content))
	//是不是有script标签
	doc, _ := goquery.NewDocumentFromReader(strings.NewReader(string(unsafe)))
	nodes := doc.Find("script").Nodes
	if len(nodes) > 0 {
		//有script标签
		doc.Find("script").Remove()
		converter := md.NewConverter("", true, nil)
		html, _ := doc.Html()
		markdown, _ := converter.ConvertString(html)
		//再次转换为markdown
		cr.Content = markdown
	}
	//当文章简介是空的时，则从内容中切出100个字符串充当简介
	if cr.Abstract == "" {
		//汉字截取先转换为rune数组
		//在取子串之前先判断cr.Content的长度是否大于100，如果小于等于100，则直接将其赋值给cr.Abstract 防止取子串时发生越界错误
		abs := []rune(doc.Text())
		//将content转换为html 并且过滤xss 以及获取中文内容
		if len(abs) > 100 {
			cr.Abstract = string(abs[:100])
		} else {
			cr.Abstract = string(abs)
		}
	}

	//不穿banner_id 去后台随机选一张封面
	if cr.BannerID == 0 {
		var bannerIDList []uint
		global.DB.Model(models.BannerModel{}).Select("id").Scan(&bannerIDList)
		if len(bannerIDList) == 0 {
			res.FailedWithMsg("没有banner数据", c)
			return
		}
		//随机选择一张banner封面
		rand.Seed(time.Now().UnixNano())
		cr.BannerID = bannerIDList[rand.Intn(len(bannerIDList))]
	}
	//查banner_id下的banner_url
	var bannerurl string
	err = global.DB.Model(models.BannerModel{}).Where("id=?", cr.BannerID).Select("path").Scan(&bannerurl).Error
	if err != nil {
		res.FailedWithMsg("banner不存在", c)
		return
	}
	//查用户头像
	var avatar string
	err = global.DB.Model(models.UserModel{}).Where("id=?", userId).Select("avatar").Scan(&avatar).Error
	if err != nil {
		res.FailedWithMsg("用户不存在", c)
		return
	}
	now := time.Now().Format("2006-01-02 15:04:05")
	article := models.ArticleModel{
		CreatedAt:    now,
		UpdatedAt:    now,
		Title:        cr.Title,
		Keyword:      cr.Title,
		Abstract:     cr.Abstract,
		Content:      cr.Content,
		UserID:       userId,
		UserNickName: userNickName,
		UserAvatar:   avatar,
		Category:     cr.Category,
		Source:       cr.Source,
		Link:         cr.Link,
		BannerID:     cr.BannerID,
		BannerUrl:    bannerurl,
		Tags:         cr.Tags,
	}
	//判断文章标题是否存在  标题是不能重复的
	if article.IsExistData() {
		res.FailedWithMsg("文章已存在", c)
		return
	}
	//创建文章
	err = article.Create()
	if err != nil {
		global.Log.Error(err)
		res.FailedWithMsg(err.Error(), c)
		return
	}
	go es_ser.AsyncArticleByFullText(article.ID, article.Title, article.Content)
	res.FailedWithMsg("文章添加成功", c)
}
